#include "stdafx.h"
#include "jtfDesktop.h"
#include "jtf.h"
#include "jtfBaseState.h"
#include "Desktop.h"
#include "customException.h"
#include <sstream>
#include <cassert>

CJtfDesktop::CJtfDesktop(CDesktop* pDesktop) : mpDesktop(pDesktop), mjobjDesktop(0), mReflection(pDesktop)
{
  CJniEnvironment jni;
  JtfDesktopClass jtfDesktop;
  jobject jobjDesktop = jtfDesktop.Constructor.New(VARGS);
  SetJtfDesktop(jobjDesktop);
}

CJtfDesktop::CJtfDesktop(CDesktop* pDesktop, BSTR hostname, LONG port) : mpDesktop(pDesktop), mjobjDesktop(0), mReflection(pDesktop)
{
  CJniEnvironment jni;
  JtfDesktopClass jtfDesktop;
  CComBSTR completeHostname(hostname);
  std::wstringstream tmp;
  tmp << hostname << L':' << port;
  CJniString jshlp(tmp.str());
  jobject jobjDesktop = jtfDesktop.ConstructorEx.New(VARGS, jshlp.JString());
  SetJtfDesktop(jobjDesktop);
}

CJtfDesktop::~CJtfDesktop()
{
  CJniEnvironment jni;
  jni.Env()->DeleteGlobalRef(mjobjDesktop);
}

void CJtfDesktop::Attach(BSTR moduleNamePattern, BSTR commandLinePattern, BSTR techDomains)
{
  CJniEnvironment jni;  
  JtfDesktopClass jtfDesktop;
  CJtfBaseState bs(moduleNamePattern, commandLinePattern, L"", techDomains);
  jtfDesktop.AttachEx.Invoke(mjobjDesktop, bs.GetExecutable(), bs.GetCommandLine(), bs.GetTechDomainsArray());
}

void CJtfDesktop::DetachAll()
{
  CJniEnvironment jni;  
  JtfDesktopClass jtfDesktop;
  jtfDesktop.DetachAll.Invoke(mjobjDesktop);
}

IDispatch* CJtfDesktop::ExecuteBasestate(BSTR executable, BSTR commandLine, BSTR mainWindowLocator, BSTR techDomains)
{
  CJniEnvironment jni;  
  JtfDesktopClass jtfDesktop;
  CJtfBaseState bs(executable, commandLine, mainWindowLocator, techDomains);
  CJniLocalReference<jobject> jobjMainWindow = jtfDesktop.ExecuteBaseState.Invoke(mjobjDesktop, bs.GetBaseState());
  jni.DoExceptionHandling();
  return mpDesktop->CreateDispTestObject(jobjMainWindow.Detach());
}

IDispatch* CJtfDesktop::ExecuteBrowserBasestate(BSTR executable, BSTR url, BSTR mainWindowLocator, BSTR techDomains)
{
  CJniEnvironment jni;  
  JtfDesktopClass jtfDesktop;
  CJtfBaseState bs(executable, url, mainWindowLocator, techDomains);
  CJniLocalReference<jobject> jobjMainWindow = jtfDesktop.ExecuteBaseState.Invoke(mjobjDesktop, bs.GetBrowserBaseState());
  jni.DoExceptionHandling();
  return mpDesktop->CreateDispTestObject(jobjMainWindow.Detach());
}

IDispatch* CJtfDesktop::Find(BSTR locator)
{
  CJniEnvironment jni;  
  JtfAbstractTestObjectClass jtfAbstractTestObject;
  CJniString hlpLocator(locator);
  CJniLocalReference<jobject> jobjResult = jtfAbstractTestObject.Find.Invoke(mjobjDesktop, hlpLocator.JString());
  jni.DoExceptionHandling();
  return mpDesktop->CreateDispTestObject(jobjResult.Detach());
}

IDispatch* CJtfDesktop::FindAll(BSTR locator)
{
  CJniEnvironment jni;  
  JtfAbstractTestObjectClass jtfAbstractTestObject;
  CJniString hlpLocator(locator);
  CJniLocalReference<jobject> jobjResult = jtfAbstractTestObject.FindAll.Invoke(mjobjDesktop, hlpLocator.JString());
  jni.DoExceptionHandling();
  return mpDesktop->CreateDispTestObjectList(jobjResult.Detach());
}

IDispatch* CJtfDesktop::GetChildren()
{
  CJniEnvironment jni;  
  JtfTestObjectClass jtfTestObject;
  CJniLocalReference<jobject> jobjResult = jtfTestObject.GetChildren.Invoke(mjobjDesktop);
  jni.DoExceptionHandling();
  return mpDesktop->CreateDispTestObjectList(jobjResult.Detach());
}

void CJtfDesktop::GetOption(BSTR optionName, VARIANT* pValue)
{
  JtfDesktopClass jtfDesktop;
  CJniString strOptionName(optionName);
  CJniLocalReference<jobject> jobjValue = jtfDesktop.GetOption.Invoke(mjobjDesktop, strOptionName.JString());
  if (!jobjValue)
    throw CustomException(1000, L"Jtf Desktop Wrapper", L"Option not set.");
  mReflection.JobjectToVariant(jobjValue.Detach(), pValue); // CHECK
}

void CJtfDesktop::GetTechDomainOption(BSTR optionName, BSTR techdomain, VARIANT* pValue)
{
  JtfTechDomainClass jtfTechDomain;
  CJniString strTechDomainName(techdomain);
  CJniLocalReference<jobject> jobjTechDomain = jtfTechDomain.Constructor.New(VARGS, strTechDomainName.JString());
  if (!jobjTechDomain)
    throw CustomException(1000, L"Jtf Desktop Wrapper", L"Invalid TechDomain name.");
  JtfDesktopClass jtfDesktop;
  CJniString strOptionName(optionName);
  CJniLocalReference<jobject> jobjValue = jtfDesktop.GetTechDomainOption.Invoke(mjobjDesktop, strOptionName.JString(), jobjTechDomain.Get());
  if (!jobjValue)
    throw CustomException(1000, L"Jtf Desktop Wrapper", L"Option not set.");
  mReflection.JobjectToVariant(jobjValue.Detach(), pValue); // CHECK
}

void CJtfDesktop::SetOption(BSTR optionName, VARIANT optionValue)
{
  CJniLocalReference<jobject> jobjValue = mReflection.VariantToJobject(&optionValue);
  if (!jobjValue)
    throw CustomException(1000, L"Jtf Desktop Wrapper", L"Invalid option value.");
  CJniString strOptionName(optionName);
  JtfDesktopClass jtfDesktop;
  jtfDesktop.SetOption.Invoke(mjobjDesktop, strOptionName.JString(), jobjValue.Get());
}

void CJtfDesktop::SetTechDomainOption(BSTR techdomain, BSTR optionName, VARIANT optionValue)
{
  JtfTechDomainClass jtfTechDomain;
  CJniString strTechDomainName(techdomain);
  CJniLocalReference<jobject> jobjTechDomain = jtfTechDomain.Constructor.New(VARGS, strTechDomainName.JString());
  if (!jobjTechDomain)
    throw CustomException(1000, L"Jtf Desktop Wrapper", L"Invalid TechDomain name.");
  CJniLocalReference<jobject> jobjValue = mReflection.VariantToJobject(&optionValue);
  if (!jobjValue)
    throw CustomException(1000, L"Jtf Desktop Wrapper", L"Invalid option value.");
  CJniString strOptionName(optionName);
  JtfDesktopClass jtfDesktop;
  jtfDesktop.SetTechDomainOption.Invoke(mjobjDesktop, strOptionName.JString(), jobjValue.Get(), jobjTechDomain.Get());
}

void CJtfDesktop::ResetAllOptions()
{
  JtfDesktopClass jtfDesktop;
  jtfDesktop.ResetAllOptions.Invoke(mjobjDesktop);
}

void CJtfDesktop::SetJtfDesktop(jobject jobjJtfDesktop)
{
  assert(!mjobjDesktop);
  CJniEnvironment jni;
  if (jobjJtfDesktop)
  { 
    jni.Env()->NewGlobalRef(jobjJtfDesktop);
    mjobjDesktop = jobjJtfDesktop;
  }
}
